package cumeo89.chii.client.entry;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Attr;
import com.google.gwt.xml.client.Node;

import cumeo89.chii.client.ui.ExtendedPanel;
import cumeo89.chii.client.ui.NamedPanel;
import cumeo89.chii.client.util.XMLUtil;

public abstract class AbstractRenderer implements Renderer, EventListener {

	private Entry entry;
	private Node node;
	private Widget widget;

	protected void initWidget(Widget widget) {
		if (this.widget != null) {
			throw new IllegalStateException("AbstractRenderer.initWidget() can"
					+ "be called only once.");
		}
		this.widget = widget;
		widget.sinkEvents(Event.ONCLICK);
		//// Kho^ng hoa.t do^.ng vi` pha?i go.i sau khi element da~ dc attach
		// DOM.setEventListener(widget.getElement(), this);
	}

	public void notifyChildSelected() {
		// DO NOTHING
	}

	public void addRenderer(Renderer child) {
		if (child.getRenderedNode().getNodeType() == Node.ATTRIBUTE_NODE) {
			if (getAttributeContainer() != null) {
				getAttributeContainer().setWidget(
						((Attr) child.getRenderedNode()).getName(),
						child.getWidget());
				doEventTrick(child);
			}
		} else {
			if (getChildContainer() != null) {
				getChildContainer().add(child.getWidget());
				doEventTrick(child);
			}
		}
	}

	public void insertRenderer(Renderer child, Renderer before) {
		if (child.getRenderedNode().getNodeType() == Node.ATTRIBUTE_NODE) {
			throw new UnsupportedOperationException();
		} else {
			if (getChildContainer() != null) {
				getChildContainer().insert(child.getWidget(),
						before.getWidget());
				doEventTrick(child);
			}
		}
	}

	/*
	 * Go.i ha`m nay` sau khi add de^? Renderer con nha^.n dc events
	 */
	public void doEventTrick(Renderer child) {
		if (child instanceof AbstractRenderer) {
			DOM.setEventListener(child.getWidget().getElement(),
					(AbstractRenderer) child);
		}
	}

	public void removeRenderer(Renderer child) {
		if (child.getRenderedNode().getNodeType() == Node.ATTRIBUTE_NODE) {
			if (getAttributeContainer() != null) {
				getAttributeContainer().removeWidget(
						((Attr) child.getRenderedNode()).getName());
			}
		} else {
			if (getChildContainer() != null) {
				getChildContainer().remove(child.getWidget());
			}
		}
	}

	protected NamedPanel getAttributeContainer() {
		if (widget instanceof NamedPanel) {
			return (NamedPanel) widget;
		}
		return null;
	}

	protected ExtendedPanel getChildContainer() {
		if (widget instanceof ExtendedPanel) {
			return (ExtendedPanel) widget;
		}
		return null;
	}

	public Node getRenderedNode() {
		return node;
	}

	public Widget getWidget() {
		return widget;
	}

	public void prepareWidget(Node node, boolean selected) {
		this.node = node;
		if (selected) {
			widget.addStyleDependentName("selected");
		} else {
			widget.removeStyleDependentName("selected");
		}
	}

	public void onBrowserEvent(Event evt) {
		switch (DOM.eventGetType(evt)) {
		case Event.ONCLICK:
			entry.setSelected(node == entry.getSelectedNode() ? null : node);
			evt.stopPropagation();
			evt.preventDefault();
			return;
		}
		widget.onBrowserEvent(evt);
	}

	public Node getFirstNode() {
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			if (node.hasAttributes()) {
				return node.getAttributes().item(0);
			}
			if (XMLUtil.getFirstNotEmptyChild(node) != null) {
				return XMLUtil.getFirstNotEmptyChild(node);
			}
		}
		return node;
	}

	public Node getLastNode() {
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			if (XMLUtil.getLastNotEmptyChild(node) != null) {
				return XMLUtil.getLastNotEmptyChild(node);
			}
			if (node.hasAttributes()) {
				return node.getAttributes().item(
						node.getAttributes().getLength() - 1);
			}
		}
		return node;
	}

	public Node getLeftNode(Node child) {
		return getPreviousNode(child);
	}

	public Node getRightNode(Node child) {
		return getNextNode(child);
	}

	public Node getAboveNode(Node child) {
		return getPreviousNode(child);
	}

	public Node getBottomNode(Node child) {
		return getNextNode(child);
	}

	private Node getPreviousNode(Node child) {
		if (child.getNodeType() == Node.ATTRIBUTE_NODE) {
			int i = XMLUtil.getIndexOf((Attr) child, node);
			return i > 0 ? node.getAttributes().item(i - 1) : null;
		}
		if (XMLUtil.getPreviousNotEmptySilbling(child) == null
				&& node.hasAttributes()) {
			return node.getAttributes().item(
					node.getAttributes().getLength() - 1);
		}
		return XMLUtil.getPreviousNotEmptySilbling(child);
	}

	private Node getNextNode(Node child) {
		if (child.getNodeType() == Node.ATTRIBUTE_NODE) {
			int i = XMLUtil.getIndexOf((Attr) child, node);
			return i < node.getAttributes().getLength() - 1 ? node
					.getAttributes().item(i + 1) : XMLUtil
					.getFirstNotEmptyChild(node);
		}
		return XMLUtil.getNextNotEmptySilbling(child);
	}

	public Entry getEntry() {
		return entry;
	}

	public void setEntry(Entry entry) {
		this.entry = entry;
	}

}
